home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
User's Choice Windows CD
/
User's Choice Windows CD (CMS Software)(1993).iso
/
misc1
/
iv26_w30.zip
/
EXAMPLES
/
IDRAW
/
PDMENU.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-30
|
12KB
|
438 lines
/*
* Copyright (c) 1987, 1988, 1989 Stanford University
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Stanford not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. Stanford makes no representations about
* the suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
* IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* Implements pulldown menu classes.
*/
#include "istring.h"
#include "pdmenu.h"
#include <InterViews/event.h>
#include <InterViews/font.h>
#include <InterViews/frame.h>
#include <InterViews/painter.h>
#include <InterViews/sensor.h>
#include <InterViews/shape.h>
#include <InterViews/world.h>
/* Define the initial number of elements to allocate space for. */
static const int INITIALSIZE = 15;
/*
* PullDownMenuBar starts with no currently active or stored
* activators although it allocates some initial space to store them.
*/
PullDownMenuBar::PullDownMenuBar () {
cur = nil;
sizeactivators = INITIALSIZE;
numactivators = 0;
activators = new PullDownMenuActivator*[sizeactivators];
}
/*
* Free storage allocated for the dynamic array.
*/
PullDownMenuBar::~PullDownMenuBar () {
delete activators;
}
/*
* Enter stores an interior activator and tells it it can get its
* highlight painter from us.
*/
void PullDownMenuBar::Enter (PullDownMenuActivator* act) {
if (numactivators == sizeactivators) {
GrowActivators();
}
activators[numactivators++] = act;
act->SetHighlighterParent(this);
}
/*
* Contains returns true if the child is one of the bar's activators
* or one of the activators' commands.
*/
boolean PullDownMenuBar::Contains (Interactor* child) {
for (int i = 0; i < numactivators; i++) {
if (activators[i] == child) {
return true;
}
}
for (i = 0; i < numactivators; i++) {
if (activators[i]->Contains(child)) {
return true;
}
}
return false;
}
/*
* MenuActive returns true if any of the bar's activators have opened
* a menu.
*/
boolean PullDownMenuBar::MenuActive () {
return cur != nil;
}
/*
* MenuShouldActivate returns true if any of the bar's activators
* EXCEPT the given one have opened a menu.
*/
boolean PullDownMenuBar::MenuShouldActivate (PullDownMenuActivator* act) {
return cur != nil && cur != act;
}
/*
* MenuActivate highlights the given activator, opens the activator's
* menu, and stores it as the currently active activator.
*/
void PullDownMenuBar::MenuActivate (PullDownMenuActivator* act) {
act->Highlight(true);
act->Open();
cur = act;
}
/*
* MenuDeactivate closes the currently active activator's menu,
* unhighlights the activator, and stores no more active activators.
*/
void PullDownMenuBar::MenuDeactivate () {
cur->Close();
cur->Highlight(false);
cur = nil;
}
/*
* GrowActivators increases the dynamic array's size to make room for
* more activators to be stored.
*/
void PullDownMenuBar::GrowActivators () {
PullDownMenuActivator** oldacts = activators;
sizeactivators += INITIALSIZE/2;
activators = new PullDownMenuActivator*[sizeactivators];
memmove(activators, oldacts, numactivators * sizeof(PullDownMenuActivator*));
delete oldacts;
}
/*
* PullDownMenuActivator stores the bar it belongs to and its text
* label. It starts off with an empty menu and no stored commands
* although it allocates some initial space to store the commands. It
* must catch the same mouse button PullDownMenuCommand catches.
*/
PullDownMenuActivator::PullDownMenuActivator (PullDownMenuBar* b,
const char* n) {
b->Enter(this);
bar = b;
name = strdup(n ? n : "");
menu = new ShadowFrame(nil,5,5);
menu->SetCanvasType(CanvasSaveUnder);
sizecommands = INITIALSIZE;
numcommands = 0;
commands = new PullDownMenuCommand*[sizecommands];
input = new Sensor(onoffEvents);
input->CatchButton(DownEvent, LEFTMOUSE);
input->CatchButton(UpEvent, LEFTMOUSE);
}
/*
* Free storage allocated for members.
*/
PullDownMenuActivator::~PullDownMenuActivator () {
delete name;
delete menu;
delete commands;
}
/*
* SetMenu sets the menu's actual contents.
*/
void PullDownMenuActivator::SetMenu (Scene* box) {
menu->Insert(box);
}
/*
* Handle works together with the bar to determine whether any
* activator has opened or should open a menu and accordingly tells
* the bar to deactivate or activate an activator.
*/
void PullDownMenuActivator::Handle (Event& e) {
switch (e.eventType) {
case DownEvent:
if (!bar->MenuActive()) {
bar->MenuActivate(this);
while (e.eventType != UpEvent) {
Read(e);
if (e.eventType == UpEvent) {
bar->MenuDeactivate();
}
if (bar->Contains(e.target)) {
e.target->Handle(e);
}
}
}
break;
case UpEvent:
break;
case OnEvent:
if (bar->MenuShouldActivate(this)) {
bar->MenuDeactivate();
bar->MenuActivate(this);
}
break;
case OffEvent:
break;
}
}
/*
* Enter stores an interior command and tells it it can get its
* highlight painter from our bar like us too.
*/
void PullDownMenuActivator::Enter (PullDownMenuCommand* cmd) {
if (numcommands == sizecommands) {
GrowCommands();
}
commands[numcommands++] = cmd;
cmd->SetHighlighterParent(bar);
}
/*
* Contains returns true if the command is one of the activator's
* commands.
*/
boolean PullDownMenuActivator::Contains (Interactor* cmd) {
for (int i = 0; i < numcommands; i++) {
if (commands[i] == cmd) {
return true;
}
}
return false;
}
/*
* Open inserts the menu into the scene with the menu's top left
* corner aligned with the activator's bottom left corner.
*/
void PullDownMenuActivator::Open () {
World* world = GetWorld();
Coord l = 0;
Coord b = 0;
GetRelative(l, b, world);
world->InsertPopup(menu, l, b, TopLeft);
}
/*
* Close makes the activator's menu disappear.
*/
void PullDownMenuActivator::Close () {
menu->Parent()->Remove(menu);
}
/*
* Reconfig pads the activator's shape to accomodate its text label.
* Basing padding on the font in use ensures the padding will change
* proportionally with changes in the font's size.
*/
static const float WIDTHPAD = 1.0;/* fraction of font->Width(EM) */
static const float CMDHTPAD = 0.1;/* fraction of font->Height() */
static const float ACTHTPAD = 0.2;/* fraction of font->Height() */
static const char* EM = "m"; /* widest alphabetic character in any font */
void PullDownMenuActivator::Reconfig () {
Highlighter::Reconfig();
Font* font = output->GetFont();
int xpad = round(WIDTHPAD * font->Width(EM));
int ypad = round(ACTHTPAD * font->Height());
shape->width = font->Width(name) + (2 * xpad);
shape->height = font->Height() + (2 * ypad);
shape->Rigid(shape->width - xpad, 0, 2 * ypad, 0);
}
/*
* Redraw displays the text label.
*/
void PullDownMenuActivator::Redraw (Coord l, Coord b, Coord r, Coord t) {
output->ClearRect(canvas, l, b, r, t);
output->Text(canvas, name, name_x, name_y);
}
/*
* Resize calculates the text label's position.
*/
void PullDownMenuActivator::Resize () {
Font* font = output->GetFont();
name_x = max(0, (xmax - font->Width(name) + 1) / 2);
name_y = (ymax - font->Height() + 1) / 2;
}
/*
* GrowCommands increases the dynamic array's size to make room for
* more commands to be stored.
*/
void PullDownMenuActivator::GrowCommands () {
PullDownMenuCommand** oldcmds = commands;
sizecommands += INITIALSIZE/2;
commands = new PullDownMenuCommand*[sizecommands];
memmove(commands, oldcmds, numcommands * sizeof(PullDownMenuCommand*));
delete oldcmds;
}
/*
* PullDownMenuCommand stores the activator it belongs to and its text
* labels. It catches only one mouse button to prevent the user from
* accidentally executing a command upon another button's release.
*/
PullDownMenuCommand::PullDownMenuCommand (PullDownMenuActivator* a,
const char* n, const char* k) {
if (a != nil) {
a->Enter(this);
}
activator = a;
name = strdup(n ? n : "");
key = strdup(k ? k : "");
input = new Sensor(onoffEvents);
input->CatchButton(UpEvent, LEFTMOUSE);
}
PullDownMenuCommand::~PullDownMenuCommand () {
delete name;
delete key;
}
/*
* Highlight or unhighlight the command when the mouse passes
* over and execute the command when the user releases the button
* types its associated character (mapped by the program).
*/
void PullDownMenuCommand::Handle (Event& e) {
switch (e.eventType) {
case OnEvent:
Highlight(true);
break;
case OffEvent:
Highlight(false);
break;
case UpEvent:
Execute(e);
Highlight(false);
break;
case KeyEvent:
activator->Highlight(true);
activator->Flush();
Execute(e);
activator->Highlight(false);
break;
}
}
/*
* Execute carries out the command's purpose.
*/
void PullDownMenuCommand::Execute (Event&) {
/* define it in your subclass */
}
/*
* Reconfig pads the command's shape to accomodate its text labels.
*/
void PullDownMenuCommand::Reconfig () {
Highlighter::Reconfig();
Font* font = output->GetFont();
int xpad = round(WIDTHPAD * font->Width(EM));
int ypad = round(CMDHTPAD * font->Height());
shape->width = font->Width(name) + (2 * xpad);
shape->width += font->Width(key) + (2 * xpad);
shape->height = font->Height() + (2 * ypad);
shape->Rigid(0, hfil, 0, 0);
}
/*
* Redraw displays the text labels.
*/
void PullDownMenuCommand::Redraw (Coord l, Coord b, Coord r, Coord t) {
output->ClearRect(canvas, l, b, r, t);
output->Text(canvas, name, name_x, name_y);
output->Text(canvas, key, key_x, key_y);
}
/*
* Resize calculates the text labels' positions.
*/
void PullDownMenuCommand::Resize () {
Font* font = output->GetFont();
int xpad = round(WIDTHPAD * font->Width(EM));
name_x = xpad;
name_y = (ymax - font->Height() + 1) / 2;
key_x = xmax - font->Width(key) - xpad;
key_y = name_y;
}
/*
* PullDownMenuDivider listens to no events so it will neither
* highlight itself nor execute any command.
*/
PullDownMenuDivider::PullDownMenuDivider () : (nil, nil, nil) {
Listen(noEvents);
}
/*
* Redraw displays a horizontal line spanning the canvas.
*/
void PullDownMenuDivider::Redraw (Coord l, Coord b, Coord r, Coord t) {
output->ClearRect(canvas, l, b, r, t);
Coord hy = ymax / 2;
output->Line(canvas, l, hy, r, hy);
}